//go:build !nofido

package fido

import (
	"bytes"
	"fmt"

	"github.com/keys-pub/go-libfido2"
)

type Device struct {
	Device *libfido2.Device
	Info   *libfido2.DeviceInfo
}

func Setup(rpID, pin string, cdh []byte, device Device) ([]byte, error) {
	attest, err := device.Device.MakeCredential(
		cdh,
		libfido2.RelyingParty{
			ID:   rpID,
			Name: "hmac-secret",
		},
		libfido2.User{
			ID:   bytes.Repeat([]byte{0x01}, 16),
			Name: "hmac-secret",
		},
		libfido2.ES256,
		pin,
		&libfido2.MakeCredentialOpts{
			Extensions: []libfido2.Extension{libfido2.HMACSecretExtension},
			RK:         libfido2.True,
		},
	)
	if err != nil {
		return []byte{}, err
	}

	return attest.CredentialID, nil
}

func GetHmacSecret(rpID, pin string, cdh, credentialID, salt []byte, device Device) ([]byte, error) {
	assertion, err := device.Device.Assertion(
		rpID,
		cdh,
		[][]byte{credentialID},
		pin,
		&libfido2.AssertionOpts{
			Extensions: []libfido2.Extension{libfido2.HMACSecretExtension},
			HMACSalt:   salt,
		},
	)
	if err != nil {
		return []byte{}, err
	}

	return assertion.HMACSecret, nil
}

func GetPluggedDevices() ([]Device, error) {
	devices := []Device{}
	locs, err := libfido2.DeviceLocations()
	if err != nil {
		return devices, fmt.Errorf("while getting locations: %w", err)
	}
	if len(locs) == 0 {
		return devices, fmt.Errorf("no devices")
	}

	for _, loc := range locs {
		device, err := libfido2.NewDevice(loc.Path)
		if err != nil {
			return devices, fmt.Errorf("while getting device from path: %w", err)
		}
		info, err := device.Info()
		if err != nil {
			return devices, fmt.Errorf("while getting info: %w", err)
		}
		devices = append(devices, Device{
			Device: device,
			Info:   info,
		})
	}
	return devices, nil
}

func GetUUID() ([]byte, error) {
	devices, err := GetPluggedDevices()
	if err != nil {
		return []byte{}, err
	}
	return devices[0].Info.AAGUID, nil
}
